

#include <iostream>
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
bool TokenizeString(string &str, string &option_name,
                    vector<string> &option_value);
inline void StringToUpperCase(string &str)
{
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

int main()
{
    string str = "DEFINITION_DV= ( 1, 1.0 | airfoil | 0, 0.05 ); ( 1, 1.0 | airfoil | 0, 0.10 ); ( 1, 1.0 | airfoil | 0, 0.15 ); ( 1, 1.0 | airfoil | 0, 0.20 ); ( 1, 1.0 | airfoil | 0, 0.25 ); ( 1, 1.0 | airfoil | 0, 0.30 ); ( 1, 1.0 | airfoil | 0, 0.35 ); ( 1, 1.0 | airfoil | 0, 0.40 ); ( 1, 1.0 | airfoil | 0, 0.45 ); ( 1, 1.0 | airfoil | 0, 0.50 ); ( 1, 1.0 | airfoil | 0, 0.55 ); ( 1, 1.0 | airfoil | 0, 0.60 ); ( 1, 1.0 | airfoil | 0, 0.65 ); ( 1, 1.0 | airfoil | 0, 0.70 ); ( 1, 1.0 | airfoil | 0, 0.75 ); ( 1, 1.0 | airfoil | 0, 0.80 ); ( 1, 1.0 | airfoil | 0, 0.85 ); ( 1, 1.0 | airfoil | 0, 0.90 ); ( 1, 1.0 | airfoil | 0, 0.95 ); ( 1, 1.0 | airfoil | 1, 0.05 ); ( 1, 1.0 | airfoil | 1, 0.10 ); ( 1, 1.0 | airfoil | 1, 0.15 ); ( 1, 1.0 | airfoil | 1, 0.20 ); ( 1, 1.0 | airfoil | 1, 0.25 ); ( 1, 1.0 | airfoil | 1, 0.30 ); ( 1, 1.0 | airfoil | 1, 0.35 ); ( 1, 1.0 | airfoil | 1, 0.40 ); ( 1, 1.0 | airfoil | 1, 0.45 ); ( 1, 1.0 | airfoil | 1, 0.50 ); ( 1, 1.0 | airfoil | 1, 0.55 ); ( 1, 1.0 | airfoil | 1, 0.60 ); ( 1, 1.0 | airfoil | 1, 0.65 ); ( 1, 1.0 | airfoil | 1, 0.70 ); ( 1, 1.0 | airfoil | 1, 0.75 ); ( 1, 1.0 | airfoil | 1, 0.80 ); ( 1, 1.0 | airfoil | 1, 0.85 ); ( 1, 1.0 | airfoil | 1, 0.90 ); ( 1, 1.0 | airfoil | 1, 0.95 )";
    string option_name;
    vector<string> option_value;
    TokenizeString(str, option_name, option_value);

    string s1{"1"}, s2{"2"}, s3{"2"};
    // 小于为 -1  等于为 0  大于为 1
    cout << "\n"
         << s1.compare(s2) << "\n"
         << s2.compare(s3) << "\n"
         << s2.compare(s1) << "\n";
    return 0;
}

bool TokenizeString(string &str, string &option_name,
                    vector<string> &option_value)
{
    const string delimiters(" ()[]{}:,\t\n\v\f\r");
    // cout << delimiters << "\n";
    // check for comments or empty string
    string::size_type pos, last_pos;
    pos = str.find_first_of("%");
    if ((str.length() == 0) || (pos == 0))
    {
        // str is empty or a comment line, so no option here
        return false;
    }
    if (pos != string::npos)
    {
        // remove comment at end if necessary
        str.erase(pos);
    }

    // look for line composed on only delimiters (usually whitespace)
    pos = str.find_first_not_of(delimiters);
    if (pos == string::npos)
    {
        return false;
    }

    // find the equals sign and split string
    string name_part, value_part;
    pos = str.find("=");
    if (pos == string::npos)
    {
        cerr << "Error in TokenizeString(): "
             << "line in the configuration file with no \"=\" sign."
             << endl;
        cout << "Look for: " << str << endl;
        cout << "str.length() = " << str.length() << endl;
        throw(-1);
    }
    name_part = str.substr(0, pos);
    value_part = str.substr(pos + 1, string::npos);
    //cout << "name_part  = |" << name_part  << "|" << endl;
    //cout << "value_part = |" << value_part << "|" << endl;

    // the first_part should consist of one string with no interior delimiters
    last_pos = name_part.find_first_not_of(delimiters, 0);
    pos = name_part.find_first_of(delimiters, last_pos);
    if ((name_part.length() == 0) || (last_pos == string::npos))
    {
        cerr << "Error in CConfig::TokenizeString(): "
             << "line in the configuration file with no name before the \"=\" sign."
             << endl;
        throw(-1);
    }
    if (pos == string::npos)
        pos = name_part.length();
    option_name = name_part.substr(last_pos, pos - last_pos);
    last_pos = name_part.find_first_not_of(delimiters, pos);
    if (last_pos != string::npos)
    {
        cerr << "Error in TokenizeString(): "
             << "two or more options before an \"=\" sign in the configuration file."
             << endl;
        throw(-1);
    }
    StringToUpperCase(option_name);

    //cout << "option_name = |" << option_name << "|" << endl;
    //cout << "pos = " << pos << ": last_pos = " << last_pos << endl;

    // now fill the option value vector
    option_value.clear();
    last_pos = value_part.find_first_not_of(delimiters, 0);
    pos = value_part.find_first_of(delimiters, last_pos);
    while (string::npos != pos || string::npos != last_pos)
    {
        // add token to the vector<string>
        option_value.push_back(value_part.substr(last_pos, pos - last_pos));
        // skip delimiters
        last_pos = value_part.find_first_not_of(delimiters, pos);
        // find next "non-delimiter"
        pos = value_part.find_first_of(delimiters, last_pos);
    }
    if (option_value.size() == 0)
    {
        cerr << "Error in TokenizeString(): "
             << "option " << option_name << " in configuration file with no value assigned."
             << endl;
        throw(-1);
    }
    vector<string> tmp1{option_value};
#if 1
    cout << "option value(s) = ";
    for (unsigned int i = 0; i < option_value.size(); i++)
        cout << option_value[i] << " ";
    cout << endl;
#endif

    // look for ';' DV delimiters attached to values
    // 防止这种情况  2;
    vector<string>::iterator it;
    it = option_value.begin();
    while (it != option_value.end())
    {
        if (it->compare(";") == 0)
        {
            it++;
            continue;
        }

        pos = it->find(';');
        if (pos != string::npos)
        {
            string before_semi = it->substr(0, pos);
            string after_semi = it->substr(pos + 1, string::npos);
            if (before_semi.empty())
            {
                *it = ";";
                it++;
                option_value.insert(it, after_semi);
            }
            else
            {
                *it = before_semi;
                it++;
                vector<string> to_insert;
                to_insert.push_back(";");
                if (!after_semi.empty())
                    to_insert.push_back(after_semi);
                option_value.insert(it, to_insert.begin(), to_insert.end());
            }
            it = option_value.begin(); // go back to beginning; not efficient
            continue;
        }
        else
        {
            it++;
        }
    }
    vector<string> tmp2{option_value};
#if 1
    cout << "\n";
    cout << "option value(s) = ";
    for (unsigned int i = 0; i < option_value.size(); i++)
        cout << option_value[i] << " ";
    cout << endl;
#endif
    // remove any consecutive ";"
    it = option_value.begin();
    bool semi_at_prev = false;
    while (it != option_value.end())
    {
        if (semi_at_prev)
        {
            if (it->compare(";") == 0)
            {
                option_value.erase(it);
                it = option_value.begin();
                semi_at_prev = false;
                continue;
            }
        }
        if (it->compare(";") == 0)
        {
            semi_at_prev = true;
        }
        else
        {
            semi_at_prev = false;
        }
        it++;
    }
    vector<string> tmp3{option_value};
#if 1
    cout << "\n";
    cout << "option value(s) = ";
    for (unsigned int i = 0; i < option_value.size(); i++)
        cout << option_value[i] << " ";
    cout << endl;
#endif
    int sz = tmp1.size();
    for (int i = 0; i < sz; ++i)
    {
        if (tmp1[i] != tmp2[i] || tmp1[i] != tmp3[i])
            cout << "not equal"
                 << "\n";
    }
    return true;
}
